package cn.lix.sc.rpc.commons.aop;


import cn.lix.sc.rpc.commons.annotations.LogPrinter;
import cn.lix.sc.rpc.commons.constants.LogLevel;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.MDC;
import org.springframework.beans.factory.InitializingBean;

import java.util.concurrent.LinkedBlockingQueue;

/**
 * 需要自己配置该类
 * @date 2021/7/7
 * @author lix
 * @email sclx1220@163.com
 */
@Aspect
public class LogsAspect implements InitializingBean {

    private final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(this.getClass());

    private final LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(128);

    private final Thread innerThread = new Thread(Thread.currentThread().getThreadGroup(), () -> {
        for (; ; ) {
            try {
                queue.take().run();
            } catch (InterruptedException e) {
                log.error(e.getMessage(), e);
            }
        }
    }, "LogsAspect-inner-thread");

    @Around("@annotation(logPrinter)")
    public Object setLog(ProceedingJoinPoint point, LogPrinter logPrinter) throws Throwable {
        String shortString = point.toShortString();
        String mark = logPrinter.mark();
        String requestId = MDC.get("REQUEST_ID");
        queue.offer(() -> {
            MDC.put("REQUEST_ID", requestId);
            log(logPrinter.value(), shortString.concat("[").concat(mark).concat("入参").concat("]:").concat(JSON.toJSONString(point.getArgs())));
        });
        Object res = point.proceed();
        queue.offer(() -> {
            MDC.put("REQUEST_ID", requestId);
            log(logPrinter.value(), shortString.concat("[").concat(mark).concat("出参").concat("]:").concat(JSON.toJSONString(res)));
        });
        return res;
    }

    private void log(LogLevel level, String value) {
        switch (level) {
            case INFO:
                log.info(value);
                break;
            case DEBUG:
                log.debug(value);
                break;
            case WARN:
                log.warn(value);
                break;
            case ERROR:
                log.error(value);
                break;
            default:
                log.trace(value);
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        innerThread.start();
    }
}
